package impl;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import ch.ethz.ssh2.Session;
import dto.CommandDto;
import model.Command;
import model.LinuxInfo;
import service.LinuxLinkService;
import toolkit.tianshi.common.model.Response;

/**
 * @author zhangLin
 */
@SuppressWarnings("ALL")
public class LinuxLinkServiceImpl implements LinuxLinkService {

    private static ThreadFactory namedThreadFactory;
    private final static ExecutorService executorService = new ThreadPoolExecutor(5, 200,
                                                                                  0L, TimeUnit.MILLISECONDS,
                                                                                  new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());;

    @Override
    public Response<String> executeCommand(CommandDto commandDtos) {
        Response<String> response = Response.newResponse();
        try {
            StringBuffer stringBuffer = new StringBuffer();
            CompletionService<String>
                    completionService = new ExecutorCompletionService<String>(executorService);
            for (LinuxInfo linuxInfo : commandDtos.getHostsDto()) {
                completionService.submit(command(linuxInfo,commandDtos));
            }
            //添加多线程end
            for (int i =0 ;i < commandDtos.getHostsDto().size();i++) {
                String ret = completionService.take().get();
                stringBuffer.append(ret).append("\n");
            }
            response.setResult(stringBuffer.toString());
        }catch (Exception e){
            e.printStackTrace();
            response.setError(e.getMessage());
        }
        return response;
    }

    private Callable<String> command(LinuxInfo linuxInfo,CommandDto commandDto){
        Callable callable = () -> {
            ch.ethz.ssh2.Connection conn = null;
            Session sess = null;
            try {
                conn = new ch.ethz.ssh2.Connection(linuxInfo.getIp(), linuxInfo.getPort());
                conn.connect();
                boolean isAuthenticated = conn.authenticateWithPassword(linuxInfo.getUserName(), linuxInfo.getPassword());
                if(isAuthenticated){
                    sess = conn.openSession();
                    /**
                     * 执行结果
                     */
                    InputStream so = sess.getStdout();
                    /**
                     * 错误结果
                     */
                    InputStream err = sess.getStderr();
                    /**
                     * 执行命令
                     */
                    OutputStream out = sess.getStdin();
                    /**
                     * 执行命令每次只能执行一条
                     */
                    sess.execCommand("/bin/bash");
                    for ( Command command : commandDto.getCommandsDto() ) {
                        byte[] buffer = new byte[500];
                        if (err.read(buffer) > 0){
                            System.out.println(command.getCom() + new String(buffer, 0, err.read(buffer)));
                        } else {
                            System.out.println(command.getCom() + new String(buffer, 0, so.read(buffer)));
                        }
                        out.write(command.getCom().getBytes());
                    }

                }else{
                    System.out.println("IP【" + linuxInfo.getIp() + "】connected fail, password is " + linuxInfo.getPassword());
                }
            }catch (Exception e){
                System.out.println("IP【" + linuxInfo.getIp() + "】changed fail: " + e.getMessage());
            }finally{
                if (sess != null){
                    sess.close();
                }
                if (conn != null){
                    conn.close();
                }
                System.out.println("changed end!");
            }
            return null;
        };
        return callable;
    }
}
